import json
from pathlib import Path
from typing import Any, Literal, TypeAlias
import numpy
from pydantic import BaseModel, Field, field_validator
from .gdimData import GdimJsonTable, GdimTableCell
from .tables import FieldMetadata, TableCollection, TableData
from .terminologies import Units

SingleValue: TypeAlias = float | int | str | np.number | bool | None
SingleNumber: TypeAlias = float | int | np.number
GeneralValue: TypeAlias = SingleValue | list[SingleValue]

class UnitResult(BaseModel):
    """Save calculation result in a single value format."""
    name: str
    title: str
    unit: Units
    value: GeneralValue
    description: str | None
    model_config: Any
    def model_post_init(self, __context: Any) -> Any:
        ...
    @field_validator
    def convert_numpy_number(cls, v):
        ...

class SingleResult:
    """Save calculation result in a dictionary format. It's used to save a single value result."""
    def __init__(self, result: list[UnitResult]):
        ...
    def __str__(self) -> str:
        """Return a user-friendly string representation of the SingleResult."""
        ...
    def __repr__(self) -> str:
        """Return a developer-friendly string representation of the SingleResult."""
        ...
    @property
    def result(self) -> list[UnitResult]:
        ...
    def __getitem__(self, key: Any) -> UnitResult:
        ...
    @property
    def title_to_name(self) -> dict[str, str]:
        """Return the title to name mapping."""
        ...
    @property
    def name_values(self) -> dict[str, GeneralValue]:
        """Return the value as {name: value}."""
        ...
    @property
    def title_values(self) -> dict[str, GeneralValue]:
        """Return the value as {title: value}."""
        ...
    @property
    def values(self) -> list[GeneralValue]:
        ...
    @property
    def names(self) -> list[str]:
        ...
    @property
    def titles(self) -> list[str]:
        ...
    @property
    def units(self) -> list[Units]:
        ...
    @property
    def descriptions(self) -> list[str]:
        ...
    def convert_to_table_data(self, joiner: str = ",") -> TableData:
        """
        Convert the SingleResult to a TableData object.
        
        Parameters
        ----------
        joiner: str, default: ","
            The joiner to be used to join the list values to be a single string.
        """
        ...
    def export_doc_context(self, precision: Any = None, joiner: str = ",") -> dict[str, SingleValue]:
        """
        Export the result to a dictionary list text for documentation.
        
        Parameters
        ----------
        precision: dict[str, int | None], default: None
            The precision used to format the values to string. The keys are the names the result.
        
        joiner: str, default: ","
            The joiner to be used to join the list values to be a single string.
        
        Returns
        -------
        dict[str, Any]
            The context of the result.
            The key is the name of the result, the value is the value of the result.
            A special key "doc_keys_strcut" is added to the context, which is used to describe the structure of the keys for the result.
        
        Note
        ----
        If the value is a list, the value will be joined by the joiner. So each value of the keys can only be a single value.
        """
        ...
    def serialize(self) -> dict:
        """
        Serialize the SingleResult object to a dictionary.
        
        This method converts the SingleResult object into a dictionary format that can be
        easily serialized to JSON or other formats. All UnitResult objects and their
        metadata are preserved.
        
        Returns
        -------
        dict
            A dictionary containing all SingleResult information:
            - 'results': List of serialized UnitResult objects
            - 'title_to_name': Mapping of titles to names
        
        Examples
        --------
        >>> result = SingleResult(...)
        >>> serialized = result.serialize()
        >>> # Can be saved to JSON
        >>> import json
        >>> json_str = json.dumps(serialized)
        """
        ...
    def deserialize(cls, data_dict: dict) -> Any:
        """
        Deserialize a SingleResult object from a dictionary.
        
        This class method reconstructs a SingleResult object from a dictionary created
        by the serialize() method. All UnitResult objects and metadata are properly restored.
        
        Parameters
        ----------
        data_dict : dict
            Dictionary containing serialized SingleResult information, typically
            created by the serialize() method
        
        Returns
        -------
        SingleResult
            Reconstructed SingleResult object with all UnitResult objects preserved
        
        Examples
        --------
        >>> # Load from serialized data
        >>> result = SingleResult.deserialize(serialized_data)
        >>>
        >>> # Or from JSON
        >>> import json
        >>> data_dict = json.loads(json_str)
        >>> result = SingleResult.deserialize(data_dict)
        """
        ...

class ComplexResult:
    """Used to save combination of tabledata result, tablecollection result and single result."""
    def __init__(self, table_data: Any = None, table_collection: Any = None, single_result: Any = None):
        ...
    def export_doc_context(self, key_type: Literal[Any, Any] = "name", table_key: str = "table_value", precision: Any = None) -> dict[Any]:
        """
        Export the table result and single result to a dictionary list text for documentation.
        
        Parameters
        ----------
        key_type: Literal["name", "title"], default: "name"
            The type of key to be used for the context.
        
        table_key: str, default: "table_value"
            The key name for the table data.
        
        precision: dict[str, int | None], default: None
            The precision used to format the values to string. The keys are the names of the result.
        """
        ...

class ToGdimJsonTable:
    """Convert a TableData, TableCollection or SingleResult to a json format so that it can be rendered on Gdim."""
    def __init__(self, data: Any = None, columns: Any = None, precision: Any = None, group_by: Any = None, main_table: Any = None):
        """
        Initialize the ToGdimJsonTable object.
        
        Parameters
        ----------
        data: SingleResult | TableData | TableCollection | None, default: None
            The data to be converted to a json format.
        
        columns: list[str] | None, default: None
            The columns to be converted to a json format. It should be the column names of the result.
        
        precision: dict[str, int] | None, default: None
            The precision to be converted to a json format. The keys are the column names of the result.
        
        group_by: str | None, default: None
            The column name to be grouped by.
            If None, the "group_by" will be the first column with the same name in all tables.
        
        main_table: str | None, default: None
            The name of the main table.
            If None, the table with the least number of rows will be used as the main table.
        
        Note
        ----
        This class can only general a json table each time which means for TableCollection, it will be merged into a single table by
        columns, group_by and main_table.
        """
        ...
    def convert(self) -> GdimJsonTable:
        """Convert the result to a GdimJsonTable object."""
        ...

class DocData(BaseModel):
    """Save the result in a format that can be used to generate a .docx document."""
    data: dict[str, Any]
    doc_keys_struct: dict[str, Any]
    def to_json_serializable(self) -> dict[str, Any]:
        """
        Return a JSON serializable copy of the DocData.
        
        Returns
        -------
        dict[str, Any]
            A dictionary with 'data' and 'doc_keys_struct' keys,
            where all Path objects have been converted to strings.
        """
        ...
    def export_data_to_json(self, file_path: str) -> Any:
        """
        Export the data to a JSON file with Path objects converted to strings.
        
        Parameters
        ----------
        file_path : str
            The path where to save the JSON file.
        """
        ...
    def export_keys_to_json(self, file_path: str) -> Any:
        """
        Export the doc keys structure to a JSON file with Path objects converted to strings.
        
        Parameters
        ----------
        file_path : str
            The path where to save the JSON file.
        """
        ...
    def export_all_to_json(self, file_path: str) -> Any:
        """
        Export both data and doc keys structure to a JSON file with Path objects converted to strings.
        
        Parameters
        ----------
        file_path : str
            The path where to save the JSON file.
        """
        ...

class CoordinateSystem(BaseModel):
    """The model defined a coordinate system."""
    name: Literal[Any, Any, Any, Any, Any, Any, Any, Any, Any, Any] | None
    zoneMethod: Literal[Any, Any] | None
    zoneNumber: int | None
    centralMeridian: float | None
    refPointLongitude: float | None
    refPointLatitude: float | None
    refPointX: float | None
    refPointY: float | None
    elevationDatum: str | None
    yAxisDirection: Literal[Any, Any] | None

class GeoReferenceInfo(BaseModel):
    """The geo reference information of a dataset, such as a picture."""
    file_name: str | None
    bounds: dict[Any, float] | None
    transform: list[float] | None
    raster_size: dict[Any, int] | None
    nodata_value: float | None
    time_info: str | None
